// $codepro.audit.disable variableShouldBeFinal, emptyMethod, lossOfPrecisionInCast, closeInFinally, closeWhereCreated
// Variables are supposed to be modified, cannot be final
// Empty methods are required to override abstract methods
// Loss of precision in casting does not affect the game
// Closing action is guaranteed to be executed
/**
 * Required imports.
 */

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.swing.JButton;
import javax.swing.JOptionPane;

/**
 * Controller constructor
 * @author Hung Lac
 * @version 1.0
 */
public class Controller {

	/**
	 * Field model.
	 */
	public Model model;

	/**
	 * Field view.
	 */
	public View view;

	/**
	 * Constructor for Controller class Translates changes in model to view
	 * 
	 * @param m
	 * @param v
	 * 
	 */
	public Controller(Model m, View v) {
		model = m;
		view = v;
		view.mntmNew.addMouseListener(new NewGameListener());
		view.btnTravel.addActionListener(new TravelListener());
		view.btnRepairfuel.addActionListener(new FuelListener());
		view.mntmSave.addActionListener(new SaveListener());
		view.mntmLoad.addActionListener(new LoadListener());
		view.btnNews.addActionListener(new BuyNewsListener());
	}

	/**
	 * Method toString.
	 * @return String
	 */
	@Override
	public String toString() {
		return this.toString();
	}

	/**
	 * Method dist.
	 * @param a Point
	 * @param b Point
	 * @return int
	 */
	public int dist(Point a, Point b) {
		int res;
		res = (int) Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2));
		return res;
	}

	/**
	 * BuyNewsListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class BuyNewsListener implements ActionListener {

		/**
		 * Method actionPerformed.
		 * @param arg0 ActionEvent
		 * @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
		 */
		@Override
		public void actionPerformed(ActionEvent arg0) {
			int response = JOptionPane
					.showConfirmDialog(view,
							"It costs 5 credits for a piece of news." +
							"\n Do you want to buy news?");
			if (response == JOptionPane.YES_OPTION) {
				model.getPlayer().setCredit(model.getPlayer().getCredits() - 5);
				view.setCurrency();
				int index = 0;
				while (!model
						.getPlayer()
						.getLocation()
						.equals(model.getUniverse().getPlanet(index)
								.getLocation())) {
					index++;
				}
				if (model.getUniverse().getPlanet(index).getNews() == -1){
					JOptionPane.showMessageDialog(view,
							"There is no special events on this planet!");
				}
				else {
					JOptionPane.showMessageDialog(view, GoodsInfo.Ie[model
							.getUniverse().getPlanet(index).getNews()]);
				}
			}
		}

		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}
	}

	/**
	 * SaveListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class SaveListener implements ActionListener {

		/**
		 * Method actionPerformed.
		 * @param arg0 ActionEvent
		 * @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
		 */
		@Override
		public void actionPerformed(ActionEvent arg0) {
			if (model.getUniverse() == null) {
				JOptionPane.showMessageDialog(view,
						"You have not start a game yet!");
			} else {
				int response = JOptionPane.showConfirmDialog(view,
						"Are you sure you want to save this game?");
				if (response == JOptionPane.YES_OPTION) {
					try {
						FileOutputStream fileOut = new FileOutputStream(
								"savedGame.ser");
						ObjectOutputStream out = new ObjectOutputStream(fileOut);
						out.writeObject(model);
						out.close();
						fileOut.close();
					} catch (IOException i) {
						i.printStackTrace();
					}
				}
			}
		}

		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}
	}

	/**
	 * LoadListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class LoadListener implements ActionListener {
		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}

		/**
		 * Method actionPerformed.
		 * @param arg0 ActionEvent
		 * @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
		 */
		@Override
		public void actionPerformed(ActionEvent arg0) {
			int response = JOptionPane.showConfirmDialog(view,
					"Are you sure you want to load a game?");
			if (response == JOptionPane.YES_OPTION) {
				try {
					FileInputStream fileIn = new FileInputStream(
							"savedGame.ser");
					ObjectInputStream in = new ObjectInputStream(fileIn);
					model = (Model) in.readObject();
					System.out.println("Loading model... ");
					in.close();
					fileIn.close();
				} catch (IOException i) {
					JOptionPane.showMessageDialog(view,
							"There is no saved game in the database!");
					i.printStackTrace();
					return;
				} catch (ClassNotFoundException c) {
					System.out.println(".Model class not found");
					c.printStackTrace();
					return;
				}
				view.dispose();
				view = new View(model);
				new Controller(model, view);
				int index = 0;
				while (!model
						.getPlayer()
						.getLocation()
						.equals(model.getUniverse().getPlanet(index)
								.getLocation())) {
					index++;
				}
				view.setHealth();
				view.setFuel();
				view.setCurrency();
				view.setPlanetName(index);
				view.setResource(index);
				view.setTechLevel(index);
				view.setBay();
				view.setMarket(index);
				view.setSell();
				view.drawNav();
				for (int i = 0; i < view.buy.length; i++) {
					view.buy[i].addMouseListener(new BuyListener(view.buy[i],
							i, 0));
					view.sell[i].addMouseListener(new SellListener(view.buy[i],
							i, 0));
				}
				view.repaint();
			}
		}
	}

	/**
	 * FuelListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class FuelListener implements ActionListener {
		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}

		/**
		 * Method actionPerformed.
		 * @param arg0 ActionEvent
		 * @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
		 */
		@Override
		public void actionPerformed(ActionEvent arg0) {
			if (model.getShip().getFuel() == 20) {
				JOptionPane.showMessageDialog(view, "You have a full tank!");
			} else {
				FuelRefill frame = new FuelRefill(model, view);
				frame.setVisible(true);
			}
		}
	}

	/**
	 * TravelListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class TravelListener implements ActionListener {
		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}

		/**
		 * Method actionPerformed.
		 * @param arg0 ActionEvent
		 * @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
		 */
		@Override
		public void actionPerformed(ActionEvent arg0) {
			if (model.getPlayer().getTravel().equals(new Point(-1, -1))) {
				JOptionPane.showMessageDialog(view,
						"You must select a planet to travel!");
			} else if (model.getPlayer().getTravel()
					.equals(model.getPlayer().getLocation())) {
				JOptionPane.showMessageDialog(view,
						"This planet is the current planet!");
			} else if (dist(model.getPlayer().getLocation(), model.getPlayer()
					.getTravel()) <= model.getShip().getFuel() * 3 / 2) {

				model.getShip().setFuel(
						model.getShip().getFuel()
								- dist(model.getPlayer().getLocation(), model
										.getPlayer().getTravel()) * 2 / 3);
				view.lblFuel.setText("Fuel: " + model.getShip().getFuel());
				model.getPlayer().setLocation(model.getPlayer().getTravel());
				int index = 0;
				while (index < model.getUniverse().getPlanetArray().length - 1) {
					Planet planet = model.getUniverse().getPlanet(index);
					if (planet.getLocation()
							.equals(model.getPlayer().getTravel())) {
						break;
					}
					index++;
				}

				/*
				 * Random travel event.
				 */
				int rand = (int) (Math.random() * 4);
				if (rand < 2) {
					new TravelEvent(model, view, (int) (Math.random() * 5));
				} else {
					new PlanetEvent(model, view, (int) (Math.random() * model
							.getUniverse().getPlanet(index).getTech()), index);
				}
				for (int i = 0; i < view.buy.length; i++) {
					view.buy[i].removeMouseListener(view.buy[i]
							.getMouseListeners()[1]);
					view.sell[i].removeMouseListener(view.sell[i]
							.getMouseListeners()[1]);
					view.buy[i].addMouseListener(new BuyListener(view.buy[i],
							i, index));
					view.sell[i].addMouseListener(new SellListener(
							view.sell[i], i, index));
				}
				view.setMarket(index);
				view.setPlanetName(index);
				view.setResource(index);
				view.setTechLevel(index);
				view.drawNav();
				view.repaint();

			} else{
				JOptionPane.showMessageDialog(view, "Out of Range!");
			}

		}
	}

	/**
	 * NewGameListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class NewGameListener implements MouseListener {
		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}

		/**
		 * Method mouseClicked.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseClicked(MouseEvent)
		 */
		@Override
		public void mouseClicked(MouseEvent arg0) {
		}

		/**
		 * Method mouseEntered.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseEntered(MouseEvent)
		 */
		@Override
		public void mouseEntered(MouseEvent arg0) {
		}

		/**
		 * Method mouseExited.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseExited(MouseEvent)
		 */
		@Override
		public void mouseExited(MouseEvent arg0) {
		}

		/**
		 * Method mousePressed.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mousePressed(MouseEvent)
		 */
		@Override
		/**
		 * Sets up a new Game
		 * 
		 * @param arg0
		 * 
		 * 
		 */
		public void mousePressed(MouseEvent arg0) {
			SpaceTraderPlayer frame = new SpaceTraderPlayer(model, view);
			frame.setVisible(true);
		}

		/**
		 * Method mouseReleased.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseReleased(MouseEvent)
		 */
		@Override
		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}
	}

	/**
	 * BuyListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class BuyListener implements MouseListener {
		/**
		 * Field x.
		 */
		/**
		 * Field i.
		 */
		public int i, x;

		/**
		 * Field jButton.
		 */
		public JButton jButton;

		/**
		 * Constructor for BuyListener.
		 * @param jButton JButton
		 * @param i int
		 * @param x int
		 */
		public BuyListener(JButton jButton, int i, int x) {
			// TODO Auto-generated constructor stub
			this.i = i;
			this.x = x;
			this.jButton = jButton;
		}

		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}

		/**
		 * Method mouseClicked.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseClicked(MouseEvent)
		 */
		@Override
		public void mouseClicked(MouseEvent arg0) {
		}

		/**
		 * Method mouseEntered.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseEntered(MouseEvent)
		 */
		@Override
		public void mouseEntered(MouseEvent arg0) {
		}

		/**
		 * Method mouseExited.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseExited(MouseEvent)
		 */
		@Override
		public void mouseExited(MouseEvent arg0) {
		}

		/**
		 * Method mousePressed.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mousePressed(MouseEvent)
		 */
		@Override
		public void mousePressed(MouseEvent arg0) {
			Planet planet = model.getUniverse().getPlanet(x);
			int count = planet.getMarket().getGoodsArray()[i]
					.getCount();
			if (count == 0){
				JOptionPane.showMessageDialog(view, "Out Of Stock!.");
			}
			else {
				SpaceTraderBuy frame = new SpaceTraderBuy(model, jButton, view,
						i, x);
				frame.setVisible(true);
			}
		}

		/**
		 * Method mouseReleased.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseReleased(MouseEvent)
		 */
		@Override
		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}
	}

	/**
	 * SellListener
	 * @author Hung Lac
	 * @version 1.0
	 */
	public class SellListener implements MouseListener {
		/**
		 * Field x.
		 */
		/**
		 * Field i.
		 */
		public int i, x;

		/**
		 * Field jButton.
		 */
		public JButton jButton;

		/**
		 * Constructor for SellListener.
		 * @param jButton JButton
		 * @param i int
		 * @param x int
		 */
		public SellListener(JButton jButton, int i, int x) {
			// TODO Auto-generated constructor stub
			this.i = i;
			this.x = x;
			this.jButton = jButton;
		}

		/**
		 * Method toString.
		 * @return String
		 */
		@Override
		public String toString() {
			return this.toString();
		}

		/**
		 * Method mouseClicked.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseClicked(MouseEvent)
		 */
		@Override
		public void mouseClicked(MouseEvent arg0) {
		}

		/**
		 * Method mouseEntered.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseEntered(MouseEvent)
		 */
		@Override
		public void mouseEntered(MouseEvent arg0) {
		}

		/**
		 * Method mouseExited.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseExited(MouseEvent)
		 */
		@Override
		public void mouseExited(MouseEvent arg0) {
		}

		/**
		 * Method mousePressed.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mousePressed(MouseEvent)
		 */
		@Override
		public void mousePressed(MouseEvent arg0) {
			Planet planet = model.getUniverse().getPlanet(x);
			if (planet.getMarket().getGood()[i].mtlu > model
					.getUniverse().getPlanet(x).getTech()){
				JOptionPane.showMessageDialog(view, "Not Allow to Sell!.");
			}
			else if (model.getShip().getGoodsArray()[i].getSold() == 0){
				JOptionPane.showMessageDialog(view, "Out Of Stock!.");
			}
			else {
				SpaceTraderSell frame = new SpaceTraderSell(model, jButton,
						view, i, x);
				frame.setVisible(true);
				view.repaint();
			}
		}

		/**
		 * Method mouseReleased.
		 * @param arg0 MouseEvent
		 * @see java.awt.event.MouseListener#mouseReleased(MouseEvent)
		 */
		@Override
		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}
	}

}
